/*
 * @(#)DBManager.java 0.0.1-SNAPSHOT
 * Copyright Group B
 */

package grupb.upf.DBManager.impl;

import grupb.upf.XMLHandlers.AccountHandler;
import grupb.upf.XMLHandlers.NewHandler;
import grupb.upf.XMLHandlers.PhotoHandler;
import grupb.upf.XMLHandlers.TaxonomyHandler;
import grupb.upf.XMLHandlers.VideoHandler;
import grupb.upf.XMLObjects.Account;
import grupb.upf.XMLObjects.Photo;
import grupb.upf.XMLObjects.New;
import grupb.upf.XMLObjects.Video;
import grupb.upf.DBdatasource.XmlDbDataSource;
import grupb.upf.DBManager.DBAction;
import grupb.upf.DBManager.DBActionResult;
//import java.text.MessageFormat;
import java.util.List;
import java.util.Vector;
import java.util.Properties;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.xmldb.api.base.Collection;
import org.xmldb.api.base.ResourceIterator;
import org.xmldb.api.base.ResourceSet;
import org.xmldb.api.base.XMLDBException;
import org.exist.xmldb.XQueryService;
import org.xml.sax.helpers.DefaultHandler;
import org.xmldb.api.modules.XMLResource;

/**
 * <p>This is the implementation of the interface DBManager. It is able to
 * execute actions to the DB.</p>
 *
 * @version    0.0.1-SNAPSHOT
 * @author     Group B
 */
public final class DBManager implements grupb.upf.DBManager.DBManager {
    /**
     * The logger. A new logger <code>grupb.upf.dbManager.DBManager</code>
     * is created to add the logs of this Content.
     */
    private static final Log LOG = LogFactory.getLog(DBManager.class);
    /**
     * The instance of DBManager. The getInstant() method will manage it.
     */
    private static DBManager instance = null;
    /**
     * The collection to load.
     */
    private Collection col;
    /**
     * The configProperties of the DB.
     */
    private Properties dbActions;
    /**
     * This method generates a log of actions performed to the DB.
     */
    private DBManager() {
        dbActions = new Properties();
        try {
            dbActions.load(DBManager.class.getClassLoader()
                    .getResourceAsStream("DBActions/DBActions.properties"));
        } catch (Exception ex) {
            LOG.fatal("Error loading properties", ex);
            instance = null;
        }
        XmlDbDataSource data = null;
        try {
            data = new grupb.upf.DBdatasource.impl.XmlDbDataSource();

        } catch (Exception ex) {
            LOG.fatal("Error loading the DB", ex);
            instance = null;
        }
        try {
            col = data.getCollection();
        } catch (XMLDBException ex) {
            LOG.fatal("Error getting the collection of the DB", ex);
            instance = null;
        }
    }
    /**
     * Method to execution an action to the DB.
     * @param aDBAction the action to execute
     * @return the result of the execution
     */
    @Override
    public DBActionResult execute(final DBAction aDBAction) {
        if (instance == null) {
            LOG.error("null instance");
            return null;
        }
        DBActionResult actionResult =
                new grupb.upf.DBManager.impl.DBActionResult();
        List resultList = new Vector();
        String action = dbActions.getProperty(aDBAction.getActionId());

        if (LOG.isInfoEnabled()) {
            StringBuffer sb = new StringBuffer(aDBAction.getActionId())
                    .append(": ").append(action);
            LOG.info(sb);
        }
        String [] props = aDBAction.getActionId().split("\\.");
        Object [] parameters = aDBAction.getParameters();
        //action = MessageFormat.format(action, parameters);

            if (parameters != null) {
                for (int i = 0; i < parameters.length; i++) {
                    String param = "{" + (i) + "}";
                    action = action.replaceAll("\\" + param,
                            parameters[i].toString());
                }
            }
        if (LOG.isInfoEnabled()) {
            LOG.info(action);
        }
        try {
            //if it is an XQuery
            XQueryService service =
                    (XQueryService) col.getService("XQueryService", "1.0");
            service.setProperty("indent", "yes");
            final ResourceSet result = service.query(action);
            //--------------------
            ResourceIterator i = result.getIterator();
            while (i.hasMoreResources()) {
                XMLResource r = (XMLResource) i.nextResource();
                Object obj = null;
                DefaultHandler handler = null;
                if (props[1].equalsIgnoreCase("account")) {
                    obj = new grupb.upf.XMLObjects.impl.Account();
                    handler = new AccountHandler((Account) obj);
                } else if (props[1].equalsIgnoreCase("photo")) {
                    obj = new grupb.upf.XMLObjects.impl.Photo();
                    handler = new PhotoHandler((Photo) obj);
                } else if (props[1].equalsIgnoreCase("video")) {
                    obj = new grupb.upf.XMLObjects.impl.Video();
                    handler = new VideoHandler((Video) obj);
                } else if (props[1].equalsIgnoreCase("new")) {
                    obj = new grupb.upf.XMLObjects.impl.New();
                    handler = new NewHandler((New) obj);
                }  else if (props[1].equalsIgnoreCase("taxonomies")) {
                    obj = new Vector();
                    handler = new TaxonomyHandler((List) obj);
                    //Se trata de un ID
                } else if (props[1].equalsIgnoreCase("id")) {
                    obj = (String) r.getContent();
                    resultList.add(obj);
                    actionResult.setResult(resultList);
                    return actionResult;
                } else {
                    actionResult.setErrorMsg("Error, handler not existent");
                    LOG.error("Handler not existent");
                    return actionResult;
                }
                r.getContentAsSAX(handler);
                resultList.add(obj);
            }
            actionResult.setResult(resultList);
        } catch (XMLDBException ex) {
            LOG.fatal("Error executing query", ex);
            actionResult.setException(ex);
        }
        return actionResult;
    }
    /**
     * Method to create a new Instance.
     */
    private static synchronized void createInstance() {
        if (instance == null) {
            instance = new DBManager();
        }
    }
    /**
     * Method to get an instance of the DBManager.
     * @return an instance
     */
    public static DBManager getInstance() {
        if (instance == null) {
            createInstance();
        }
        return instance;
    }
}
